package android.framework.rpc.convertor;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;


public class ObjectConvertor implements IConvertor<Object>{

	public Object convert(MemberInfo memberInfo) {
		try{
			Object obj;
			if(memberInfo.isClass()){
				if(memberInfo.isCollection()){
					obj = Array.newInstance(memberInfo.getType(), memberInfo.getArrayLength());
					int i = 0;
					for (MemberInfo objMember : memberInfo) {
						Array.set(obj, i++, convert(objMember));
					}
				}
				else{
					obj = memberInfo.getType().getDeclaredConstructor().newInstance();
					for (MemberInfo objMember : memberInfo) {
						obj.getClass().getField(objMember.getName()).set(obj, convert(objMember));
					}
				}
			}
			else{
				obj = PrimitiveHandler.convert(memberInfo);
			}
			
			return obj;
		}
		catch(Exception e){
			throw new ConvertorException("can't comvert: " + memberInfo.toString(), e);
		}
	}
	
	public MemberInfo convert(Object obj) {
		try{
			Class<?> cls = obj.getClass();
			MemberInfo memberInfo;
			
			if(PrimitiveHandler.isPrimitive(cls)){
				memberInfo = new MemberInfo(cls, PrimitiveHandler.primitiveToString(obj));
			}
			else{
				List<MemberInfo> members = new ArrayList<MemberInfo>();
				boolean iteratorable = isIteratorable(obj);
				boolean isArray = isArray(obj);
				boolean isCollection = iteratorable|| isArray;
				int arrayLength = 0;
				if(isCollection){
					if(iteratorable){
						for(Object o : (Iterable<?>)obj){
							cls = o.getClass();
							MemberInfo newMember = convert(o);
							members.add(newMember);
							arrayLength++;
						}
					}
					else{ // Array
						arrayLength = Array.getLength(obj);
						cls = cls.getComponentType();
						for (int i = 0; i < arrayLength; i++) {
							Object o = Array.get(obj, i);
							MemberInfo newMember = convert(o);
							members.add(newMember);
						}
					}
				}
				else{
					for (Field field : cls.getDeclaredFields()) {
						field.setAccessible(true);
						MemberInfo newMember = convert(field.get(obj));
						newMember.setName(field.getName());
						members.add(newMember);
					}
				}
				memberInfo = new MemberInfo(cls, members);
				memberInfo.setArrayLength(arrayLength);
				memberInfo.setCollection(isCollection);
			}
			
			return memberInfo;
		}
		catch(IllegalAccessException e){
			throw new ConvertorException(String.format("can't convert object %s to MemberInfo", obj), e);
		}
	}
	
	
	private boolean isIteratorable(Object obj){
		return obj instanceof Iterable<?>; 
	}
	
	private boolean isArray(Object obj){
		return obj.getClass().isArray();// instanceof Object[];
	}

}
